/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.objer.model;

import java.util.Date;
import java.util.TimeZone;

import org.zhiqim.git.Git;
import org.zhiqim.git.GitConfig;

import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Ints;
import org.zhiqim.kernel.util.Longs;
import org.zhiqim.kernel.util.Strings;

/**
 * Git身份对象，包括名称、邮箱、时间和时区信息，用于提交信息中表明作者或提交者
 * 格式如下：
 * 
 * 森中灵 <senyeah@qq.com> 1490791737 +0800
 *
 * @version v1.0.0 @author zouzhigang 2017-4-15 新建与整理
 */
public class PersonIdent
{
    private final String name;
    private final String email;
    private final long when;
    private final int zone;

    /*********************************************************************/
    //构造函数
    /*********************************************************************/
    
    /** 从配置中读取身份信息，多用于客户端 */
    public PersonIdent(Git git)
    {
        GitConfig config = git.getConfig();
        
        this.name = config.getCommitterName();
        this.email = config.getCommitterEmail();
        this.when = System.currentTimeMillis();
        this.zone = DateTimes.getTimeZoneMinute();
    }

    /** 指定名称、邮箱、时间和时区 */
    public PersonIdent(String name, String email, long when, int zone)
    {
        this.name = name;
        this.email = email;
        this.when = when;
        this.zone = zone;
    }
    
    /** 指定名称和邮箱，和当前时间和时区对象 */
    public PersonIdent(String name, String email, Date when, TimeZone zone)
    {
        this.name = name;
        this.email = email;
        this.when = when.getTime();
        this.zone = zone.getOffset(this.when) / (60 * 1000);
    }
    
    /** 指定名称和邮箱，取当前时间和时区 */
    public PersonIdent(String name, String email)
    {
        this.name = name;
        this.email = email;
        this.when = System.currentTimeMillis();
        this.zone = DateTimes.getTimeZoneMinute();
    }
    
    /** 从指定的身份对象中读取名称和邮箱，取当前时间和时区 */
    public PersonIdent(PersonIdent pi)
    {
        this(pi.getName(), pi.getEmail());
    }
    
    /** 从指定的身份对象中读取名称和邮箱、指定时间和时区 */
    public PersonIdent(PersonIdent pi, long when, int zone)
    {
        this.name = pi.getName();
        this.email = pi.getEmail();
        this.when = when;
        this.zone = zone;
    }
    
    /** 从指定的身份对象中读取名称和邮箱和时区，取当前时间 */
    public PersonIdent(PersonIdent pi, Date date)
    {
        this.name = pi.getName();
        this.email = pi.getEmail();
        this.when = date.getTime();
        this.zone = pi.zone;
    }
    
    /** 从指定的身份对象中读取名称和邮箱、时间和时区 */
    public PersonIdent(PersonIdent pi, Date when, TimeZone zone)
    {
        this(pi.getName(), pi.getEmail(), when, zone);
    }

    /** 解析字符串，得到身份对象 */
    public PersonIdent(String str)
    {
        int lt = str.indexOf('<');
        Asserts.asserts(lt != -1, "身份字符串要求[<]字符");
        
        int gt = str.indexOf('>', lt);
        Asserts.asserts(gt != -1, "身份字符串要求[>]字符");

        //取名称和邮箱
        this.name = str.substring(0, lt).trim();
        this.email = str.substring(lt + 1, gt).trim();
        
        int separator = str.indexOf(' ', gt + 2);
        if (separator == -1)
        {//没有时间和时区
            this.when = 0;
            this.zone = -1;
        }
        else
        {//有时间和时区
            this.when = Longs.toLong(Strings.trim(str.substring(gt + 1, separator))) * 1000;
            
            String zoneHour = Strings.trim(str.substring(separator + 1, separator + 4));
            int zoneHourInt = Ints.toInt(Strings.trimLeft(zoneHour, "+"));
            
            String zoneMin = Strings.trim(str.substring(separator + 4));
            int zoneMinInt = Ints.toInt(zoneMin);
            
            this.zone = zoneHourInt * 60 + zoneMinInt;
        }
    }

    /*********************************************************************/
    //获取属性
    /*********************************************************************/
    
    public String getName()
    {
        return name;
    }

    public String getEmail()
    {
        return email;
    }
    
    public int getZone()
    {
        return zone;
    }

    public Date getWhen()
    {
        return new Date(when);
    }

    public int getCommitTime()
    {
        return (int)(when / 1000);
    }
    
    public TimeZone getTimeZone()
    {
        StringBuilder strb = new StringBuilder(8);
        strb.append("GMT").append(toTimezone());
        return TimeZone.getTimeZone(strb.toString());
    }

    public String toExternalString()
    {
        return new StringBuilder()
            .append(name)
            .append(" <").append(email).append("> ")
            .append(when / 1000)
            .append(' ')
            .append(toTimezone())
            .toString();
    }

    private String toTimezone()
    {
        StringBuilder strb = new StringBuilder();
        strb.append(zone<0?'-':'+');
        
        int offset = zone<0?-zone:zone;
        int offsetHours = offset / 60;
        int offsetMins = offset % 60;
        
        if (offsetHours < 10)
            strb.append('0');
        strb.append(offsetHours);
        
        if (offsetMins < 10)
            strb.append('0');
        strb.append(offsetMins);
        return strb.toString();
    }
    
    /*********************************************************************/
    //hashCode&equals&toString
    /*********************************************************************/

    public int hashCode()
    {
        return getEmail().hashCode() ^ (int) when;
    }

    public boolean equals(final Object o)
    {
        if (o instanceof PersonIdent)
        {
            final PersonIdent p = (PersonIdent) o;
            return getName().equals(p.getName()) && getEmail().equals(p.getEmail()) && when == p.when;
        }
        return false;
    }

    public String toString()
    {
        return new StringBuffer()
            .append("PersonIdent[")
            .append(name).append(", ").append(email).append(", ").append(DateTimes.toDateTimeString(when))
            .append("]")
            .toString();
    }
}
